﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace T810_CAN.CAN
{
    /// <summary>
    /// CAN设备信息
    /// </summary>
    public class CanDeviceInfo
    {
        public uint DeviceType;
        public uint DeviceIndex;
        public uint CANIndex;
        public VCI_INIT_CONFIG Config;
    }

    /// <summary>
    /// CAN配置
    /// </summary>
    public class CanConfig
    {
        public UInt32 DeviceType { get; set; }
        public UInt32 DeviceIndex { get; set; }
        public UInt32 CANIndex { get; set; }
        public UInt32 AccCode { get; set; }
        public UInt32 AccMask { get; set; }
        public byte Filter { get; set; }//0或1接收所有帧。2标准帧滤波，3是扩展帧滤波。
        public byte Mode { get; set; }
        public byte Timing0 { get; set; }
        public byte Timing1 { get; set; }
    }

    /// <summary>
    /// CAN数据帧
    /// </summary>
    public class CanFrame
    {
        #region 属性
        public string Name { get; set; } //CAN帧名称

        public UInt32 ID { get; set; } //CAN帧ID

        public bool isRemote { get; set; }//标记是否是远程帧

        public bool isExternal { get; set; }//标记是否是拓展帧

        public UInt32 TimeStamp { get; set; }//时间戳

        public byte DataLen { get; set; }//数据长度

        protected byte[] _data = new byte[8];//帧数据缓冲区，供内部使用
        public byte[] Data //帧数据
        {
            get { return _data; }
            set
            {
                Buffer.BlockCopy(value, 0, _data, 0, value.Length > 8 ? 8 : value.Length);
            }
        }
        #endregion

        public CanFrame()
        {

        }

        public CanFrame(VCI_CAN_OBJ obj)
        {
            ID = obj.ID;
            isRemote = obj.RemoteFlag > 0 ? true : false;
            isExternal = obj.ExternFlag > 0 ? true : false;
            if (obj.TimeFlag > 0)//时间戳有效
            {
                TimeStamp = obj.TimeStamp;
            }
            else
            {
                TimeStamp = 0;
            }
            unsafe
            {
                Marshal.Copy((IntPtr)obj.Data, _data, 0, 8);
            }
            DataLen = obj.DataLen;
        }

        /// <summary>
        /// CAN_OBJ转CAN_Frame
        /// </summary>
        /// <param name="obj">需要转换的CAN_OBJ</param>
        /// <returns></returns>
        public static CanFrame VCI_CAN_OBJ2CAN_Frame(VCI_CAN_OBJ obj)
        {
            CanFrame frame = new CanFrame();
            frame.ID = obj.ID;
            frame.isRemote = obj.RemoteFlag > 0 ? true : false;
            frame.isExternal = obj.ExternFlag > 0 ? true : false;
            if (obj.TimeFlag > 0)//时间戳有效
            {
                frame.TimeStamp = obj.TimeStamp;
            }
            else
            {
                frame.TimeStamp = 0;
            }
            frame.DataLen = obj.DataLen;
            unsafe
            {
                Marshal.Copy((IntPtr)obj.Data, frame.Data, 0, obj.DataLen);
            }
            return frame;
        }

        /// <summary>
        /// 将本CAN帧转换为CAN_OBJ
        /// </summary>
        /// <returns></returns>
        public VCI_CAN_OBJ Get_VCI_CAN_OBJ()
        {
            VCI_CAN_OBJ obj = new VCI_CAN_OBJ();
            obj.ID = ID;
            obj.RemoteFlag = isRemote ? (byte)1 : (byte)0;
            obj.ExternFlag = isExternal ? (byte)1 : (byte)0;
            //TODO 时间戳是否有效处理
            if (TimeStamp > 0)
            {
                obj.TimeFlag = 1;
                obj.TimeStamp = TimeStamp;
            }
            else
            {
                obj.TimeFlag = 0;
                obj.TimeStamp = 0;
            }
            obj.DataLen = DataLen;
            unsafe
            {
                Marshal.Copy(_data, 0, (IntPtr)obj.Data, 8);
            }
            return obj;
        }

        /// <summary>
        /// CAN帧拷贝
        /// 未完成
        /// </summary>
        /// <param name="frame"></param>
        public void CloneTo(ref CanFrame frame)
        {
            frame.ID = this.ID;
        }

        /// <summary>
        /// 转换成字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string strRemote = isRemote ? "远程帧" : "数据帧";
            string strExternal = isExternal ? "扩展帧" : "标准帧";
            //return $"[{System.Convert.ToString(ID, 16)}] {strRemote} {strExternal} {COMMON.Common.hex2str(Data)}";
            return $"{(TimeStamp / 10000.0f).ToString("0.0000")} [{System.Convert.ToString(ID, 16)}] {COMMON.Common.hex2str(Data.Take(DataLen).ToArray())}";
        }
    }


    /// <summary>
    /// CAN硬件层封装
    /// </summary>
    public abstract class CanBase
    {
        protected CanConfig CANConfig;//CAN配置

        public bool isConnected = false;//标记CAN_USB是否连接
        public bool isOpen = false;//标记CAN_USB是否打开

        public CanBase()
        {

        }

        public CanBase(CanConfig canConfig)
        {
            CANConfig = canConfig;
        }

        ~CanBase()
        {
            ControlCAN_API.VCI_CloseDevice(CANConfig.DeviceType, CANConfig.DeviceIndex);
        }

        /// <summary>
        /// 启动设备
        /// </summary>
        public virtual void Start()
        {
            if (!this.isConnected)//设备未连接
            {
                if (!Connect_Device())//连接失败
                {
                    return;
                }
            }
            if (!this.isOpen) //未启动
            {
                Start_CAN();
            }
        }

        /// <summary>
        /// 关闭设备
        /// </summary>
        public virtual void Stop()
        {
            if (isOpen)
            {
                if (ControlCAN_API.VCI_ResetCAN(CANConfig.DeviceType, CANConfig.DeviceIndex, CANConfig.CANIndex) == 1)
                {
                    //LogHelper.INFO("CAN stop successfully");
                    this.isOpen = false;
                }
            }
        }

        /// <summary>
        /// 获取设备参数
        /// </summary>
        /// <returns></returns>
        public virtual CanConfig GetConfig()
        {
            return this.CANConfig;
        }

        /// <summary>
        /// 设置设备参数
        /// </summary>
        /// <param name="config"></param>
        public virtual void SetConfig(CanConfig config)
        {
            CANConfig.DeviceType = config.DeviceType;
            CANConfig.DeviceIndex = config.DeviceIndex;
            CANConfig.CANIndex = config.CANIndex;
            CANConfig.AccCode = config.AccCode;
            CANConfig.AccMask = config.AccMask;
            CANConfig.Filter = config.Filter;
            CANConfig.Mode = config.Mode;
            CANConfig.Timing0 = config.Timing0;
            CANConfig.Timing1 = config.Timing1;

        }

        #region CAN设备接口
        /// <summary>
        /// 查找可用设备
        /// </summary>
        /// <returns></returns>
        public abstract int Find_Device();

        /// <summary>
        /// CAN连接函数
        /// 针对不同的设备，需要重写此函数
        /// 后面可以做成抽象函数，针对CANalyst-II具化一个函数
        /// </summary>
        /// <returns></returns>
        public abstract bool Connect_Device();

        /// <summary>
        /// 断开CAN连接
        /// </summary>
        /// <returns></returns>
        public abstract bool DisConnect_Device();

        /// <summary>
        /// 启动CAN
        /// </summary>
        /// <returns></returns>
        public abstract bool Start_CAN();

        /// <summary>
        /// 停止CAN
        /// </summary>
        /// <returns></returns>
        public abstract bool Stop_CAN();

        /// <summary>
        /// 发送CAN帧
        /// </summary>
        /// <param name="frame">待发送的CAN帧</param>
        /// <returns></returns>
        public abstract bool Transmit_Frame(CanFrame frame);

        /// <summary>
        /// 发送CAN帧
        /// </summary>
        /// <returns>接收到的CAN帧</returns>
        public abstract CanFrame Receive_Frame();
        #endregion
    }

}
